# 工具函数
import configparser
from datetime import datetime
import os
import re
import yaml
import patoolib
import zipfile
import py7zr
import shutil
import chardet
import subprocess
import platform
from Logger import logger
import paramiko
from db_handler import db_handler

class MyResponse(object):
    res = {"data": "", "success": True, "msg": ""}

    def __init__(self, data, success, msg=""):
        self.res["data"] = data
        self.res["success"] = success
        self.res["msg"] = msg

    def post(self):
        return self.res


def handle_exception(err, message):
    logger.error("Error occurred：%s", err)
    return MyResponse({"err": err}, False, message).post()


def handle_success(data, message):
    return MyResponse(data, True, message).post()


# 获得指定路径下的所有文件夹名字
def get_dir(dir_path):
    return [x for x in os.listdir(dir_path) if os.path.isdir(os.path.join(dir_path, x))]


# 获取目录下文件信息列表
def get_files_info(dir_path, file_type=None):
    file_info_list = []

    with os.scandir(dir_path) as it:
        for entry in it:
            if entry.is_file():
                # 获取文件扩展名
                ext = os.path.splitext(entry.name)[1].lower()

                # 检查文件类型（如果已提供）
                if file_type is None or ext == f".{file_type.lower()}":
                    last_modified_time = datetime.fromtimestamp(entry.stat().st_mtime)
                    file_size_bytes = entry.stat().st_size
                    file_size_kb = round(file_size_bytes / 1024, 2)  # 转换为KB并保留两位小数
                    file_info = {
                        'name': entry.name,
                        'path': entry.path,
                        'size': f"{file_size_kb} kb",  # 将大小转为带"kb"的字符串
                        'lastModified': last_modified_time.strftime('%Y-%m-%d %H:%M:%S'),
                    }
                    file_info_list.append(file_info)

    return file_info_list

# 获取下文件信息列表
def get_files_info_db(project_name,file_type=None):
    file_info_list = []
    # 构建基础查询语句
    query = "SELECT file_name, file_size, modify_time FROM Script "

    # 如果指定了文件类型，则添加 WHERE 子句
    if file_type:
        query += " WHERE project_id=(SELECT id FROM project WHERE project_name= %s) and script_type = %s"
    logger.info(query)
    query += " ORDER BY file_name"
    # 执行查询
    results = db_handler.execute_query(query, (project_name,file_type) if file_type else None)
    # 处理查询结果
    if results:
        for row in results:
            file_size_kb = round(row['file_size'] / 1024, 2)  # 转换为KB并保留两位小数
            file_info = {
                'name': row['file_name'],
                'size': f"{file_size_kb} kb",
                'lastModified': row['modify_time'].strftime('%Y-%m-%d %H:%M:%S'),
            }
            file_info_list.append(file_info)

    return file_info_list


# 转小驼峰法命名
def to_lower_camel_case(x):
    s = re.sub('_([a-zA-Z])', lambda m: (m.group(1).upper()), x.lower())
    return s[0].lower() + s[1:]


# 获取全局配置文件里内容
def get_global_config():
    #path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static\global.ini')
    path =os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'global.ini')
    cf = configparser.ConfigParser()
    cf.read(path, 'utf-8')
    items = cf.items("ProjectConfig")
    data = {}
    for item in items:
        data[to_lower_camel_case(item[0])] = item[1]
    return data


# 获取本地IP
def get_local_ip():
    try:
        # 根据系统类型选择命令和编码
        if platform.system() == "Windows":
            cmd = "ipconfig"
            encoding = "gbk"
            pattern = r"IPv4 地址[ .]*: ([\d.]+)"
        else:
            cmd = "ip addr show"  # 现代Linux系统使用ip命令替代ifconfig
            encoding = "utf-8"
            pattern = r"inet (?!127\.0\.0\.1)(\d+\.\d+\.\d+\.\d+)"

        # 执行命令并解码输出
        output = subprocess.check_output(cmd, shell=True).decode(encoding)

        # 使用正则表达式匹配IP地址
        match = re.search(pattern, output)
        return match.group(1) if match else "无法获取本地 IP 地址"

    except (subprocess.CalledProcessError, AttributeError, FileNotFoundError) as e:
        return "无法获取本地 IP 地址"


# 移动文件
def move_files(src_dir, dest_dir):
    # 遍历源目录下的所有文件和子目录
    for item in os.listdir(src_dir):
        src_path = os.path.join(src_dir, item)
        dest_path = os.path.join(dest_dir, item)

        # 如果是文件，检查是否已经存在于目标目录，如果不是则移动
        if os.path.isfile(src_path):
            if not os.path.exists(dest_path):
                shutil.move(src_path, dest_path)
                print(f"Moved {src_path} to {dest_path}")


# 清理文件，限制10个
def limit_files(path, limit=10):
    # 获取路径下的文件列表，按修改时间排序
    files = sorted(os.listdir(path), key=lambda f: os.path.getmtime(os.path.join(path, f)))

    # 如果文件数量超过限制，删除最旧的文件
    if len(files) > limit:
        for file in files[:len(files) - limit]:
            file_path = os.path.join(path, file)
            try:
                # 删除文件
                os.remove(file_path)
                print(f"Deleted: {file_path}")
            except OSError as e:
                print(f"Error deleting {file_path}: {e}")


# 解压缩文件
def extract_rar(file_path, extract_path):
    try:
        file_list = []
        patoolib.extract_archive(file_path, outdir=extract_path)
    except Exception as e:
        # 处理解压缩错误
        logger.error(e)
        return False

        # 检测解压缩后文件的编码
    for root, dirs, files in os.walk(extract_path):
        for file in files:
            file_path = os.path.join(root, file)
            file_list.append(root)
            with open(file_path, 'rb') as f:
                raw_data = f.read()
                result = chardet.detect(raw_data)
                encoding = result['encoding']
                if encoding != 'utf-8':
                    # 如果编码不是 UTF-8，可以进行相应处理，例如重新编码为 UTF-8
                    try:
                        decoded_data = raw_data.decode(encoding)
                        with open(file_path, 'w', encoding='utf-8') as f:
                            f.write(decoded_data)
                    except UnicodeDecodeError:
                        # 处理解码错误
                        pass
            # 处理txt、dat文件，去除空行
            if file.endswith(('.txt', '.dat','.csv')):
                file_type = file.split('.')[-1]
                temp_filename = f"{file_path}.tmp"

                with open(file_path, 'r', encoding='utf-8') as f_in, \
                        open(temp_filename, 'w', encoding='utf-8') as f_out:
                    for line in f_in:
                        if line.strip():
                            f_out.write(line)
                # 替换原文件
                shutil.move(temp_filename, file_path)
    # 防止压缩包中嵌套一层目录
    if file_list[0] != extract_path:
        move_files(file_list[0], extract_path)
        shutil.rmtree(file_list[0])
    return True


def extract_zip(file_path, extract_path):
    try:
        file_list = []
        with zipfile.ZipFile(file_path, 'r') as zip_ref:
            # 提取所有文件，不指定编码，让 zipfile 使用默认的编码
            zip_ref.extractall(extract_path)

            # 遍历解压后的文件，检查并重命名文件名
            for file_info in zip_ref.infolist():
                encoded_file_name = file_info.filename.encode('cp437')
                try:
                    decoded_file_name = encoded_file_name.decode('gbk')
                except UnicodeDecodeError:
                    # 如果使用 gbk 解码失败，尝试使用 utf-8 解码
                    decoded_file_name = encoded_file_name.decode('utf-8', errors='ignore')

                original_file_path = os.path.join(extract_path, file_info.filename)
                new_file_path = os.path.join(extract_path, decoded_file_name)

                file_list.append(new_file_path)

                # 重命名文件
                if original_file_path != new_file_path:
                    os.rename(original_file_path, new_file_path)

        print(file_list)
        # 防止压缩包中嵌套一层目录
        if file_list[0] != extract_path:
            move_files(file_list[0], extract_path)
            shutil.rmtree(file_list[0])
    except zipfile.BadZipFile:
        print("Error: Bad zip file.")
        return False
    except zipfile.LargeZipFile:
        print("Error: The zip file is too large.")
        return False
    except Exception as e:
        print(f"An error occurred: {e}")
        return False
    return True


def extract_7z(file_path, extract_path):
    try:
        with py7zr.SevenZipFile(file_path, mode='r') as z:
            z.extractall(path=extract_path)
            # 防止压缩包中嵌套一层目录
            if (item for item in os.listdir(extract_path) if os.path.isdir(os.path.join(extract_path, item))):
                src_dir = [os.path.join(extract_path, subdirectory) for subdirectory in os.listdir(extract_path) if
                           os.path.isdir(os.path.join(extract_path, subdirectory))]
                print(src_dir[0])
                move_files(src_dir[0], extract_path)
                shutil.rmtree(src_dir[0])
        return True
    except Exception as e:
        print(f"Error: {e}")
        return False


def extract_compressed_file(zip_path, extract_path):
    # 获取压缩包文件名及后缀
    file_name, file_extension = os.path.splitext(zip_path)

    if file_extension.lower() == '.rar':
        # RAR压缩包
        return extract_rar(zip_path, extract_path)
    elif file_extension.lower() == '.zip':
        # ZIP压缩包
        return extract_zip(zip_path, extract_path)
    elif file_extension.lower() == '.7z':
        return extract_7z(zip_path, extract_path)
    else:
        # 不支持的压缩包类型
        return False


# 检查服务器是否开启CMDRunner
# def is_cmdrunner_running(host, username, password):
#     ssh = paramiko.SSHClient()
#     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#     ssh.connect(host, username=username, password=password)
#
#     stdin, stdout, stderr = ssh.exec_command('ps -ef | grep CMDRunner')
#     output = stdout.read().decode()
#
#     ssh.close()
#
#     return 'CMDRunner' in output

# 使用示例
# host = '10.58.20.24'  # 服务器IP
# username = 'root'  # 服务器用户名
# password = 'xncs.2023'  # 服务器密码
# print(is_cmdrunner_running(host, username, password))


# 目录下文件压缩成zip文件
def compress_directory_to_zip(input_dir, output_zip):
    """
    Compresses the input directory into a zip file.
    
    Args:
        input_dir (str): The path to the directory to be compressed.
        output_zip (str): The path to the output zip file.
    """
    # 创建一个ZipFile对象
    with zipfile.ZipFile(output_zip, 'w', zipfile.ZIP_DEFLATED) as zipf:
        # 遍历输入目录下的所有文件和子目录
        for root, dirs, files in os.walk(input_dir):
            for file in files:
                if not file.startswith('modified'):
                    # 构建文件的完整路径
                    file_path = os.path.join(root, file)
                    # 获取文件相对于输入目录的相对路径
                    relative_path = os.path.relpath(file_path, input_dir)
                    # 将文件添加到ZIP文件
                    zipf.write(file_path, arcname=relative_path)

